// threadtest.cc 
//	Simple test case for the threads assignment.
//
//	Create two threads, and have them context switch
//	back and forth between themselves by calling Thread::Yield, 
//	to illustratethe inner workings of the thread system.
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include "copyright.h"
#include "system.h"



//----------------------------------------------------------------------
// SimpleThread
// 	Loop 5 times, yielding the CPU to another ready thread 
//	each iteration.
//
//	"which" is simply a number identifying the thread, for debugging
//	purposes.
//----------------------------------------------------------------------
void
SimpleThread(int which)
{
    int num;
    
    for (num = 0; num < 5; num++) {
        printf("*** thread %d looped %d times\n", which, num);
        currentThread->Yield();
    }
}

//----------------------------------------------------------------------
// ThreadTest
// 	Set up a ping-pong between two threads, by forking a thread 
//	to call SimpleThread, and then calling SimpleThread ourselves.
//----------------------------------------------------------------------

void
ThreadTest()
{
    DEBUG('t', "Entering SimpleTest");

    Thread *t = new Thread("forked thread");

    //    Thread *t2 = new Thread ("my thread");
    //delete t2;

    //t2 ->Fork(SimpleThread,2);


    t->Fork(SimpleThread, 1);
    SimpleThread(0);
}


//	Simple test cases for the threads assignment.
//

//#include "copyright.h"
//#include "system.h"
#ifdef CHANGED
#include "synch.h"
#endif

#ifdef CHANGED
// --------------------------------------------------
// Test Suite
// --------------------------------------------------


// --------------------------------------------------
// Test 1 - see TestSuite() for details
// --------------------------------------------------
Semaphore t1_s1("t1_s1",0);       // To make sure t1_t1 acquires the
                                  // lock before t1_t2
Semaphore t1_s2("t1_s2",0);       // To make sure t1_t2 Is waiting on the 
                                  // lock before t1_t3 releases it
Semaphore t1_s3("t1_s3",0);       // To make sure t1_t1 does not release the
                                  // lock before t1_t3 tries to acquire it
Semaphore t1_done("t1_done",0);   // So that TestSuite knows when Test 1 is
                                  // done
Lock t1_l1("t1_l1");		  // the lock tested in Test 1

// --------------------------------------------------
// t1_t1() -- test1 thread 1
//     This is the rightful lock owner
// --------------------------------------------------
void t1_t1() {
    t1_l1.Acquire();
    t1_s1.V();  // Allow t1_t2 to try to Acquire Lock
 
    printf ("%s: Acquired Lock %s, waiting for t3\n",currentThread->getName(),
	    t1_l1.getName());
    t1_s3.P();
    printf ("%s: working in CS\n",currentThread->getName());
    for (int i = 0; i < 1000000; i++) ;
    printf ("%s: Releasing Lock %s\n",currentThread->getName(),
	    t1_l1.getName());
    t1_l1.Release();
    t1_done.V();
}

// --------------------------------------------------
// t1_t2() -- test1 thread 2
//     This thread will wait on the held lock.
// --------------------------------------------------
void t1_t2() {

    t1_s1.P();	// Wait until t1 has the lock
    t1_s2.V();  // Let t3 try to acquire the lock

    printf("%s: trying to acquire lock %s\n",currentThread->getName(),
	    t1_l1.getName());
    t1_l1.Acquire();

    printf ("%s: Acquired Lock %s, working in CS\n",currentThread->getName(),
	    t1_l1.getName());
    for (int i = 0; i < 10; i++)
	;
    printf ("%s: Releasing Lock %s\n",currentThread->getName(),
	    t1_l1.getName());
    t1_l1.Release();
    t1_done.V();
}

// --------------------------------------------------
// t1_t3() -- test1 thread 3
//     This thread will try to release the lock illegally
// --------------------------------------------------
void t1_t3() {

    t1_s2.P();	// Wait until t2 is ready to try to acquire the lock

    t1_s3.V();	// Let t1 do it's stuff
    for ( int i = 0; i < 3; i++ ) {
	printf("%s: Trying to release Lock %s\n",currentThread->getName(),
	       t1_l1.getName());
	t1_l1.Release();
    }
}

// --------------------------------------------------
// Test 2 - see TestSuite() for details
// --------------------------------------------------
Lock t2_l1("t2_l1");		// For mutual exclusion
Condition t2_c1("t2_c1");	// The condition variable to test
Semaphore t2_s1("t2_s1",0);	// To ensure the Signal comes before the wait
Semaphore t2_done("t2_done",0);     // So that TestSuite knows when Test 2 is
                                  // done

// --------------------------------------------------
// t2_t1() -- test 2 thread 1
//     This thread will signal a variable with nothing waiting
// --------------------------------------------------
void t2_t1() {
    t2_l1.Acquire();
    printf("%s: Lock %s acquired, signalling %s\n",currentThread->getName(),
	   t2_l1.getName(), t2_c1.getName());
    t2_c1.Signal(&t2_l1);
    printf("%s: Releasing Lock %s\n",currentThread->getName(),
	   t2_l1.getName());
    t2_l1.Release();
    t2_s1.V();	// release t2_t2
    t2_done.V();
}

// --------------------------------------------------
// t2_t2() -- test 2 thread 2
//     This thread will wait on a pre-signalled variable
// --------------------------------------------------
void t2_t2() {
    t2_s1.P();	// Wait for t2_t1 to be done with the lock
    t2_l1.Acquire();
    printf("%s: Lock %s acquired, waiting on %s\n",currentThread->getName(),
	   t2_l1.getName(), t2_c1.getName());
    t2_c1.Wait(&t2_l1);
    printf("%s: Releasing Lock %s\n",currentThread->getName(),
	   t2_l1.getName());
    t2_l1.Release();
}
// --------------------------------------------------
// Test 3 - see TestSuite() for details
// --------------------------------------------------
Lock t3_l1("t3_l1");		// For mutual exclusion
Condition t3_c1("t3_c1");	// The condition variable to test
Semaphore t3_s1("t3_s1",0);	// To ensure the Signal comes before the wait
Semaphore t3_done("t3_done",0); // So that TestSuite knows when Test 3 is
                                // done

// --------------------------------------------------
// t3_waiter()
//     These threads will wait on the t3_c1 condition variable.  Only
//     one t3_waiter will be released
// --------------------------------------------------
void t3_waiter() {
    t3_l1.Acquire();
    t3_s1.V();		// Let the signaller know we're ready to wait
    printf("%s: Lock %s acquired, waiting on %s\n",currentThread->getName(),
	   t3_l1.getName(), t3_c1.getName());
    t3_c1.Wait(&t3_l1);
    printf("%s: freed from %s\n",currentThread->getName(), t3_c1.getName());
    t3_l1.Release();
    t3_done.V();
}


// --------------------------------------------------
// t3_signaller()
//     This threads will signal the t3_c1 condition variable.  Only
//     one t3_signaller will be released
// --------------------------------------------------
void t3_signaller() {

    // Don't signal until someone's waiting
    
    for ( int i = 0; i < 5 ; i++ ) 
	t3_s1.P();
    t3_l1.Acquire();
    printf("%s: Lock %s acquired, signalling %s\n",currentThread->getName(),
	   t3_l1.getName(), t3_c1.getName());
    t3_c1.Signal(&t3_l1);
    printf("%s: Releasing %s\n",currentThread->getName(), t3_l1.getName());
    t3_l1.Release();
    t3_done.V();
}
 
// --------------------------------------------------
// Test 4 - see TestSuite() for details
// --------------------------------------------------
Lock t4_l1("t4_l1");		// For mutual exclusion
Condition t4_c1("t4_c1");	// The condition variable to test
Semaphore t4_s1("t4_s1",0);	// To ensure the Signal comes before the wait
Semaphore t4_done("t4_done",0); // So that TestSuite knows when Test 4 is
                                // done

// --------------------------------------------------
// t4_waiter()
//     These threads will wait on the t4_c1 condition variable.  All
//     t4_waiters will be released
// --------------------------------------------------
void t4_waiter() {
    t4_l1.Acquire();
    t4_s1.V();		// Let the signaller know we're ready to wait
    printf("%s: Lock %s acquired, waiting on %s\n",currentThread->getName(),
	   t4_l1.getName(), t4_c1.getName());
    t4_c1.Wait(&t4_l1);
    printf("%s: freed from %s\n",currentThread->getName(), t4_c1.getName());
    t4_l1.Release();
    t4_done.V();
}


// --------------------------------------------------
// t2_signaller()
//     This thread will broadcast to the t4_c1 condition variable.
//     All t4_waiters will be released
// --------------------------------------------------
void t4_signaller() {

    // Don't broadcast until someone's waiting
    
    for ( int i = 0; i < 5 ; i++ ) 
	t4_s1.P();
    t4_l1.Acquire();
    printf("%s: Lock %s acquired, broadcasting %s\n",currentThread->getName(),
	   t4_l1.getName(), t4_c1.getName());
    t4_c1.Broadcast(&t4_l1);
    printf("%s: Releasing %s\n",currentThread->getName(), t4_l1.getName());
    t4_l1.Release();
    t4_done.V();
}
// --------------------------------------------------
// Test 5 - see TestSuite() for details
// --------------------------------------------------
Lock t5_l1("t5_l1");		// For mutual exclusion
Lock t5_l2("t5_l2");		// Second lock for the bad behavior
Condition t5_c1("t5_c1");	// The condition variable to test
Semaphore t5_s1("t5_s1",0);	// To make sure t5_t2 acquires the lock after
                                // t5_t1

// --------------------------------------------------
// t5_t1() -- test 5 thread 1
//     This thread will wait on a condition under t5_l1
// --------------------------------------------------
void t5_t1() {
    t5_l1.Acquire();
    t5_s1.V();	// release t5_t2
    printf("%s: Lock %s acquired, waiting on %s\n",currentThread->getName(),
	   t5_l1.getName(), t5_c1.getName());
    t5_c1.Wait(&t5_l1);
    printf("%s: Releasing Lock %s\n",currentThread->getName(),
	   t5_l1.getName());
    t5_l1.Release();
}

// --------------------------------------------------
// t5_t1() -- test 5 thread 1
//     This thread will wait on a t5_c1 condition under t5_l2, which is
//     a Fatal error
// --------------------------------------------------
void t5_t2() {
    t5_s1.P();	// Wait for t5_t1 to get into the monitor
    t5_l1.Acquire();
    t5_l2.Acquire();
    printf("%s: Lock %s acquired, signalling %s\n",currentThread->getName(),
	   t5_l2.getName(), t5_c1.getName());
    t5_c1.Signal(&t5_l2);
    printf("%s: Releasing Lock %s\n",currentThread->getName(),
	   t5_l2.getName());
    t5_l2.Release();
    printf("%s: Releasing Lock %s\n",currentThread->getName(),
	   t5_l1.getName());
    t5_l1.Release();
}

// --------------------------------------------------
// TestSuite()
//     This is the main thread of the test suite.  It runs the
//     following tests:
//
//       1.  Show that a thread trying to release a lock it does not
//       hold does not work
//
//       2.  Show that Signals are not stored -- a Signal with no
//       thread waiting is ignored
//
//       3.  Show that Signal only wakes 1 thread
//
//	 4.  Show that Broadcast wakes all waiting threads
//
//       5.  Show that Signalling a thread waiting under one lock
//       while holding another is a Fatal error
//
//     Fatal errors terminate the thread in question.
// --------------------------------------------------
void TestSuite() {
    Thread *t;
    char *name;
    int i;
    
    // Test 1

    //printf("Starting Test 1\n");

    cout<<"Starting Test 1"<<endl;
    t = new Thread("t1_t1");
    t->Fork((VoidFunctionPtr)t1_t1,0);

    t = new Thread("t1_t2");
    t->Fork((VoidFunctionPtr)t1_t2,0);

    t = new Thread("t1_t3");
    t->Fork((VoidFunctionPtr)t1_t3,0);

    // Wait for Test 1 to complete
    for (  i = 0; i < 2; i++ ){
      t1_done.P();
    }
    
    // Test 2

    printf("Starting Test 2.  Note that it is an error if thread t2_t2\n");
    printf("completes\n");

    t = new Thread("t2_t1");
    t->Fork((VoidFunctionPtr)t2_t1,0);

    t = new Thread("t2_t2");
    t->Fork((VoidFunctionPtr)t2_t2,0);

    // Wait for Test 2 to complete
    t2_done.P();

    // Test 3

    printf("Starting Test 3\n");

    for (  i = 0 ; i < 5 ; i++ ) {
	name = new char [20];
	sprintf(name,"t3_waiter%d",i);
	t = new Thread(name);
	t->Fork((VoidFunctionPtr)t3_waiter,0);
    }
    t = new Thread("t3_signaller");
    t->Fork((VoidFunctionPtr)t3_signaller,0);

    // Wait for Test 3 to complete
    for (  i = 0; i < 2; i++ )
	t3_done.P();

    // Test 4

    printf("Starting Test 4\n");

    for (  i = 0 ; i < 5 ; i++ ) {
	name = new char [20];
	sprintf(name,"t4_waiter%d",i);
	t = new Thread(name);
	t->Fork((VoidFunctionPtr)t4_waiter,0);
    }
    t = new Thread("t4_signaller");
    t->Fork((VoidFunctionPtr)t4_signaller,0);

    // Wait for Test 4 to complete
    for (  i = 0; i < 6; i++ )
	t4_done.P();

    // Test 5

    printf("Starting Test 5.  Note that it is an error if thread t5_t1\n");
    printf("completes\n");

    t = new Thread("t5_t1");
    t->Fork((VoidFunctionPtr)t5_t1,0);

    t = new Thread("t5_t2");
    t->Fork((VoidFunctionPtr)t5_t2,0);

}
#endif

////////////////////////////
//part 2 code starts here///
////////////////////////////


//monitor variables and shared information
//setup for dynamic allocation

///////////////////////
//shared data        //
///////////////////////

//pointer to array of ints to represent visitors in the car
//int *passengers;
int *passengers;
int *limoPassengers;

//pointer to array of ints to represent visitors out of the car
//  int *outOfCar;
int *outOfCar;
int *limoOutOfCar;

//integer to keep track of number of cars in line
int inLine = 0;
int limoLine = 0;

//integer to keep track of how many people are in line to get the tickets
//taken
int ticketLineCount = 0;

int inMuseum = 0;

int driverWaiting =0;

int limoWaiting =0;

int onBench = 0;

int working = 2;



///////////////////////
//Locks              //
///////////////////////

//array of lock pointers with one lock for each car based on the index
Lock** carLock;
Lock** limoLock;

Lock *parkingLock1;

Lock *lineLock;

Lock *breakLock;


///////////////////////
//condition variables//
///////////////////////

//CV for when the driver is waiting for all the passengers 
//to get our of the car
//car CV's
Condition** driverWaitingCV;

Condition *readyToPark;

Condition** visitorExit;

Condition** canLeave;

Condition** hasKeys;

Condition** hasToken;

Condition** leaveToken;

Condition** readyToLeave;

Condition** waitToLeave;

Condition** waitExit;

Condition** waitCarLeaving;

Condition *leaving;


//limo CV's
Condition** limoWaitingCV;

Condition *limoReadyToPark;

Condition** visitorLimoExit;

Condition** limoCanLeave;

Condition** limoHasKeys;

Condition** limoHasToken;

Condition** limoLeaveToken;

Condition** limoReadyToLeave;

Condition** limoWaitToLeave;

Condition** limoWaitExit;

Condition** waitLimoLeaving;

Condition *limoLeaving;

Condition** limoTip;


Condition *waitForCars;



List *carnumbersArrive;

List *carnumbersLeave;

List *limoListToPark;

List *limoListToLeave;


Condition *Tip;
Condition *waitOnCustomers;
Condition *ticketLine;
Condition *managerWaiting;
Condition *backRoom;
Condition *waitForBreak;



//for dynamic visitor creation
struct visInfo{
  char* name;
  int carNum;
  int limoNum;
  bool limo;
  int visNum;
};



//go to museum function

void goToMuseum(){
  //get a random number between 50 and 100
  int randomNum = rand()%101 + 50;
  
  //simulate time inside the museum
  for(int i = randomNum; i>0; i--){
    currentThread->Yield();
  }
}

int sum = limoWaiting + limoLine + inLine + driverWaiting;


///////////////////////
//driver code        //
///////////////////////


//Function Car Arrive to the Museum
void driveInMuseum(int number, char* name){

  int carNum = number;


  //code for arriving at museum and getting in line
  //print message to show they have arrived
  cout<<name<<" "<<carNum<<" has arrived at the museum"<<endl;

  //atomic operation
  //get parking lock
  parkingLock1->Acquire();

  //print message to get in line
  cout<<name<<" "<<carNum<<" is getting in line to be parked"<<endl;

  //increment inLine count
  inLine++;

  carnumbersArrive->Append((void*)carNum);

  //wait for condition variable
  cout<<name<<" "<<number<<" is in line to be parked"<<endl;
  waitForCars->Signal(parkingLock1);
  readyToPark->Wait(parkingLock1);
  parkingLock1->Release();

}



void limoDriveInMuseum(int number, char* name){

  int carNum = number;


  //code for arriving at museum and getting in line
  //print message to show they have arrived
  cout<<name<<carNum<<" has arrived at the museum"<<endl;

  //atomic operation
  //get parking lock
  parkingLock1->Acquire();

  //print message to get in line
  cout<<name<<carNum<<" is getting in line to be parked"<<endl;

  //increment inLine count
  limoLine++;

  limoListToPark->Append((void*)carNum);

  cout<<name<<number<<" is in line to be parked"<<endl;
  //wait for condition variable
  waitForCars->Signal(parkingLock1);
  limoReadyToPark->Wait(parkingLock1);
 
  parkingLock1->Release();


}


void removingLimoPassengers(int number, char *name){

  int limoNum = number;


  //atomic operation
  //get lock to deal with people in car
  limoLock[limoNum]->Acquire();

  //driver meets valet and tells visitors to exit.
  cout<<"Visitors from "<<name<<limoNum<<" can now exit the limo"<<endl;
  visitorLimoExit[limoNum]->Broadcast(limoLock[limoNum]);

  //release lock
  limoLock[limoNum]->Release();


  //code for exiting the car
  //enter the car monitor
  limoLock[limoNum]->Acquire();
  
  //check if all passengers have exited the car
  if (limoPassengers[limoNum] > 0){
    //this means passengers are still in the car
    //make driver wait for the condition variable
    cout<<name<<limoNum<<" is waiting for passengers to exit"<<endl;

    limoWaitingCV[limoNum]->Wait(limoLock[limoNum]);

    cout<<name<<limoNum<<" is exiting the limo"<<endl;
    
  } else{
    //all passengers have exited
    cout<<name<<limoNum<<" is exiting the limo"<<endl;
  }
  
  //exit the monitor
  limoLock[limoNum]->Release();

}


void removingPassengers(int number, char *name){

  int carNum = number;

  //atomic operation
  //get lock to deal with people in car
  carLock[carNum]->Acquire();

  //driver meets valet and tells visitors to exit.
  cout<<"Visitors from "<<name<<" "<<carNum<<" can now exit the car"<<endl;
  visitorExit[carNum]->Broadcast(carLock[carNum]);

  //release lock
  carLock[carNum]->Release();


  //code for exiting the car
  //enter the car monitor
  carLock[carNum]->Acquire();
  
  //check if all passengers have exited the car
  //cout<<carNum<<" "<<passengers[carNum]<<endl;
  if (passengers[carNum] > 0){
    //this means passengers are still in the car
    //make driver wait for the condition variable
    cout<<name<<" "<<carNum<<" is waiting for passengers to exit"<<endl;

    driverWaitingCV[carNum]->Wait(carLock[carNum]);

    cout<<name<<" "<<carNum<<" is exiting the car"<<endl;
    
  } else{
    //all passengers have exited
    cout<<name<<" "<<carNum<<" is exiting the car"<<endl;
  }
  
  //exit the monitor
  carLock[carNum]->Release();

}

void gettingParkingToken(int number, char *name){
 
  int carNum = number;

  //get the lock
  carLock[carNum]->Acquire();
  
  //give keys to the valet
  cout<<"Driver "<<carNum<<" hands over the keys to the Valet"<<endl;
  hasKeys[carNum]->Signal(carLock[carNum]);

  //wait for a parking token from the valet
  cout<<"Driver "<<carNum<<" is waiting for a parking token"<<endl;
  hasToken[carNum]->Wait(carLock[carNum]);

  //message saying they recieved the token
  cout<<"Driver "<<carNum<<" has received a parking token"<<endl;

  //release the lock
  carLock[carNum]->Release();

}

void gettingLimoParkingToken(int number, char *name){
 
  int carNum = number;
  //get the lock
  limoLock[carNum]->Acquire();
  
  //give keys to the valet
  cout<<"Limo Driver "<<carNum<<" hands over the keys to the Valet"<<endl;
  limoHasKeys[carNum]->Signal(limoLock[carNum]);

  //wait for a parking token from the valet
  cout<<"Limo Driver "<<carNum<<" is waiting for a parking token"<<endl;
  limoHasToken[carNum]->Wait(limoLock[carNum]);

  //message saying they recieved the token
  cout<<"Limo Driver "<<carNum<<" has received a parking token"<<endl;

  //release the lock
  limoLock[carNum]->Release();

}





//*************************
//Driver Thread 



void Driver(int number){

  char* name;
  name = "Driver";
  int carNum = number;


  //car arrive at the museum
  driveInMuseum(number,name);

  //removing people from the car
  removingPassengers(number,name);

  //getting parking token from the valet
  gettingParkingToken(number,name);





  //get the lock to get in line
  lineLock->Acquire();

  //if no one is in line wake up the ticket taker
  if (ticketLineCount == 0){
    cout<<"Waking up the Ticket Taker"<<endl;
    waitOnCustomers->Signal(lineLock);
    //increment the in line count
    ticketLineCount ++;
    //get in line
    cout<<"Driver "<<carNum<<" is getting in line for the Ticket Taker"<<endl;
    ticketLine->Wait(lineLock);
  }else{
    //if people are in line just increment the count and get in line
    ticketLineCount ++;
    cout<<"Driver "<<carNum<<" is getting in line for the Ticket Taker"<<endl;
    ticketLine->Wait(lineLock);
  }

  //release the lock
  lineLock->Release();

  cout<<"Driver "<<carNum<<" is entering the museum"<<endl;
  inMuseum ++;
  goToMuseum();
  cout<<"Driver "<<carNum<<" is exiting the museum"<<endl;

  //get the lock
  carLock[carNum]->Acquire();

  //wait for everyone to exit the museum
  //if driver is alone he will not get onto the leaving CV
  if (outOfCar[carNum] > 0){
    cout<<"Driver "<<carNum<<" is waiting for everyone to exit"<<endl;
    readyToLeave[carNum]->Wait(carLock[carNum]);
  }

  //release the lock
  carLock[carNum]->Release();



  //tell the valet they want to leave
  //get in line to get a valet so the car can leave
  parkingLock1->Acquire();
  driverWaiting ++;
  cout<<"Driver "<<carNum<<" calls the Valet"<<endl;
  waitForCars->Signal(parkingLock1);

  //wait for the valet to come and help them
  cout<<"Driver "<<carNum<<" is waiting for a valet"<<endl;
  carnumbersLeave->Append((void*)carNum);
  leaving->Wait(parkingLock1);

  //release the lock
  parkingLock1->Release();

  //get the lock
  carLock[carNum]->Acquire();

  //give the parking token to the valet
  cout<<"Driver "<<carNum<<" gives his parking token to Valet"<<endl;
  leaveToken[carNum]->Signal(carLock[carNum]);

  //wait for the valet to return with the car
  cout<<"Driver "<<carNum<<" is waiting for his car"<<endl;
  waitCarLeaving[carNum]->Wait(carLock[carNum]);

  //tip the valet
  cout<<"Driver "<<carNum<<" tips the Valet"<<endl;
  Tip->Signal(carLock[carNum]);

  //wait for acknowledgement of tip from valet
  canLeave[carNum]->Wait(carLock[carNum]);

  //tell all visitors they can get in the car
  cout<<"Everyone from Car "<<carNum<<" can get in the Car"<<endl;
  waitToLeave[carNum]->Broadcast(carLock[carNum]);

  //check if driver did not have any passengers
  if(passengers[carNum] > 0){
    //if driver did have passengers wait for all of them
    //to get back in the car
    cout<<"Driver "<<carNum<<" is waiting for everyone to get in"<<endl;
    readyToLeave[carNum]->Wait(carLock[carNum]);
  }    

  //tell all visitors they are leaving the museum
  cout<<"Driver "<<carNum<<" gets into the Car"<<endl;
  cout<<"Driver "<<carNum<<" leaves Museum"<<endl;
  waitExit[carNum]->Broadcast(carLock[carNum]);

  //release the lock
  carLock[carNum]->Release();
}

void limoDriver(int number){

  char* name;
  name = "Limo Driver ";
  int carNum = number;


  limoDriveInMuseum(number,name);

  removingLimoPassengers(number,name);

  gettingLimoParkingToken(number,name);


  //get the lock
  limoLock[carNum]->Acquire();

  //wait for everyone to exit the museum
  //if driver is alone he will not get onto the leaving CV
  if (limoOutOfCar[carNum] > 0){
    cout<<"Limo Driver "<<carNum<<" is waiting for everyone to exit"<<endl;
    limoReadyToLeave[carNum]->Wait(limoLock[carNum]);
  }

  //release the lock
  limoLock[carNum]->Release();



  //tell the valet they want to leave
  parkingLock1->Acquire();
  //get in line to get a valet so the car can leave
  limoWaiting ++;
  cout<<"Limo Driver "<<carNum<<" calls the Valet"<<endl;
  waitForCars->Signal(parkingLock1);

  //wait for the valet to come and help them
  cout<<"Limo Driver "<<carNum<<" is waiting for a Valet"<<endl;
  limoListToLeave->Append((void*)carNum);
  limoLeaving->Wait(parkingLock1);

  //release the lock
  parkingLock1->Release();

  //get the lock
  limoLock[carNum]->Acquire();

  //give the parking token to the valet
  cout<<"Limo Driver "<<carNum<<" gives his parking token to Valet"<<endl;
  limoLeaveToken[carNum]->Signal(limoLock[carNum]);

  //wait for the valet to return with the car
  cout<<"Limo Driver "<<carNum<<" is waiting for his Limo"<<endl;
  waitLimoLeaving[carNum]->Wait(limoLock[carNum]);
  limoLock[carNum]->Release();

  //cout<<"Limo 8: "<<limoLock[8]<<endl;
  //cout<<"Limo 9: "<<limoLock[9]<<endl;

  limoLock[carNum]->Acquire();

  //tip the valet
  cout<<"Limo Driver "<<carNum<<" tips the Valet"<<endl;
  //cout<<carNum<<"limo Lock: "<<limoLock[carNum]<<endl;
  limoTip[carNum]->Signal(limoLock[carNum]);

  //wait for acknowledgement of tip from valet
  limoCanLeave[carNum]->Wait(limoLock[carNum]);

  //tell all visitors they can get in the car
  cout<<"Everyone from Limo "<<carNum<<" can get in the Limo"<<endl;
  limoWaitToLeave[carNum]->Broadcast(limoLock[carNum]);

  //check if driver did not have any passengers
  if(limoPassengers[carNum] > 0){
    //if driver did have passengers wait for all of them
    //to get back in the car
    cout<<"Limo Driver "<<carNum<<" is waiting for everyone to get in"<<endl;
    limoReadyToLeave[carNum]->Wait(limoLock[carNum]);
  }    

  //tell all visitors they are leaving the museum
  cout<<"Limo Driver "<<carNum<<" gets into the Limo"<<endl;
  cout<<"Limo Driver "<<carNum<<" leaves Museum"<<endl;
  limoWaitExit[carNum]->Broadcast(limoLock[carNum]);

  //release the lock
  limoLock[carNum]->Release();

}

///////////////////////
//visitor code       //
///////////////////////

void Visitor(int data){
  
  visInfo* info = (visInfo*) data;

  char* name = info->name;
  int num = info->visNum;
  
  if (info->limo){  

    int carNum = info->limoNum;
    
    //code to check for exit
    limoLock[carNum]->Acquire();
    
    //make visitor wait to exit the car
    cout<<"Visitor "<<num<<" is waiting to exit Limo "<<carNum<<endl;
    visitorLimoExit[carNum]->Wait(limoLock[carNum]);
    
    //release the lock
    limoLock[carNum]->Release();
    
    //code to exit a car
    limoLock[carNum]->Acquire();
    
    //actually exit the car
    if(limoLock[carNum]->isHeldByCurrentThread()){
      //print message so you know its happening
      cout<<"Visitor "<<num<<" is exiting Limo "<<carNum<<endl;
      //decrement the passengers in the car
      limoPassengers[carNum] --;
      //increment passengers out of the car
      limoOutOfCar[carNum] ++;
    }else{
      //print error message if thread does not have the lock
      cout<<"Current thread does not hold the lock"<<endl;
    }
    
    if(limoPassengers[carNum] == 0){
      //this means car is empty
      //signal the driver to tell them car is empty
      cout<<"All passengers have exited Limo "<<carNum<<endl;
      limoWaitingCV[carNum]->Signal(limoLock[carNum]);
    }
    
    //exit the monitor
    limoLock[carNum]->Release();
    
    //get the lock to get in line
    lineLock->Acquire();
    
    //check to see if anyone is in line to get their ticket taken
    if (ticketLineCount == 0){
      //if no one is in line wake up the ticket taker
      cout<<"Visitor "<<num<<" is waking up the Ticket Taker"<<endl;
      waitOnCustomers->Signal(lineLock);
      //increment the number of people in line
      ticketLineCount ++;
      //get in line
      cout<<"Visitor "<<num<<" is getting in line for the Ticket Taker"<<endl;
      ticketLine->Wait(lineLock);
    }else{
      //if there are people in line increment the count and get in line
      ticketLineCount ++;
      cout<<"Visitor "<<num<<" is getting in line for the Ticket Taker"<<endl;
      ticketLine->Wait(lineLock);
    }
    
    //release the lock
    lineLock->Release();
    
    //go to the museum
    cout<<"Visitor "<<num<<" is entering the museum"<<endl;
    goToMuseum();
    cout<<"Visitor "<<num<<" is exiting the museum"<<endl;
    
    //acquire the car lock
    limoLock[carNum]->Acquire();
    
    //decrement here so the last will know they are the last
    limoOutOfCar[carNum] --;
    limoPassengers[carNum] ++;
    
    //checking to see how many people are waiting for a car
    if (limoOutOfCar[carNum] > 0){
      cout<<"Visitor "<<num<<" is waiting for everyone to leave the Museum"<<endl;
      limoWaitToLeave[carNum]->Wait(limoLock[carNum]);
    }else{
      //if everyone is out of the museum tell the driver
      cout<<"All Visitors from Limo "<<carNum<<" are back"<<endl;
      limoReadyToLeave[carNum]->Signal(limoLock[carNum]);
      limoWaitToLeave[carNum]->Wait(limoLock[carNum]);
    }
    
    //cout<<passengers[carNum]<<endl;
    //decrement ahead so that the last passenger will know they are the last
    limoPassengers[carNum] --;
    
    //check if all the passengers are in the car
    if(limoPassengers[carNum] > 0){
      cout<<"Visitor "<<num<<" is getting in Limo "<<carNum<<endl;
    }else{
      //if all passengers are in the car print message and tell driver
      cout<<"Visitor "<<num<<" is getting in Limo "<<carNum<<endl;
      cout<<"All Visitors are in Limo "<<carNum<<endl;
      limoReadyToLeave[carNum]->Signal(limoLock[carNum]);
    }
    
    //wait for driver to drive off
    cout<<"Visitor "<<num<<" is waiting for Limo "<<carNum<<" to drive off"<<endl;
    limoWaitExit[carNum]->Wait(limoLock[carNum]);
    
    //release the lock
    limoLock[carNum]->Release();
  } else {
    
    
    ////////////////////////////////car code///////////////////////////
    
    int carNum = info->carNum;
    
    //code to check for exit
    carLock[carNum]->Acquire();
    
    //make visitor wait to exit the car
    cout<<"Visitor "<<num<<" is waiting to exit Car "<<carNum<<endl;
    visitorExit[carNum]->Wait(carLock[carNum]);
    
    //release the lock
    carLock[carNum]->Release();
    
    //code to exit a car
    carLock[carNum]->Acquire();
    
    //actually exit the car
    if(carLock[carNum]->isHeldByCurrentThread()){
      //print message so you know its happening
      cout<<"Visitor "<<num<<" is exiting the car"<<endl;
      //decrement the passengers in the car
      passengers[carNum] --;
      //increment passengers out of the car
      outOfCar[carNum] ++;
    }else{
      //print error message if thread does not have the lock
      cout<<"Current thread does not hold the lock"<<endl;
    }
    
    if(passengers[carNum] == 0){
      //this means car is empty
      //signal the driver to tell them car is empty
      cout<<"All passengers have exited Car "<<carNum<<endl;
      driverWaitingCV[carNum]->Signal(carLock[carNum]);
    }
    
    //exit the monitor
    carLock[carNum]->Release();
    
    //get the lock to get in line
    lineLock->Acquire();
    
    //check to see if anyone is in line to get their ticket taken
    if (ticketLineCount == 0){
      //if no one is in line wake up the ticket taker
      cout<<"Visitor "<<num<<" is waking up the Ticket Taker"<<endl;
      waitOnCustomers->Signal(lineLock);
      //increment the number of people in line
      ticketLineCount ++;
      //get in line
      cout<<"Visitor "<<num<<" is getting in line for the Ticket Taker"<<endl;
      ticketLine->Wait(lineLock);
    }else{
      //if there are people in line increment the count and get in line
      ticketLineCount ++;
      cout<<"Visitor "<<num<<" is getting in line for the Ticket Taker"<<endl;
      ticketLine->Wait(lineLock);
    }
    
    //release the lock
    lineLock->Release();
    
    //go to the museum
    cout<<"Visitor "<<num<<" is entering the museum"<<endl;
    goToMuseum();
    cout<<"Visitor "<<num<<" is exiting the museum"<<endl;
    
    //acquire the car lock
    carLock[carNum]->Acquire();
    
    //decrement here so the last will know they are the last
    outOfCar[carNum] --;
    passengers[carNum] ++;
    
    //checking to see how many people are waiting for a car
    if (outOfCar[carNum] > 0){
      cout<<"Visitor "<<num<<" is waiting for everyone to leave the Museum"<<endl;
      waitToLeave[carNum]->Wait(carLock[carNum]);
    }else{
      //if everyone is out of the museum tell the driver
      cout<<"All Visitors from car "<<carNum<<" are back"<<endl;
      readyToLeave[carNum]->Signal(carLock[carNum]);
      waitToLeave[carNum]->Wait(carLock[carNum]);
    }
    
    //cout<<passengers[carNum]<<endl;
    //decrement ahead so that the last passenger will know they are the last
    passengers[carNum] --;
    
    //check if all the passengers are in the car
    if(passengers[carNum] > 0){
      cout<<"Visitor "<<num<<" is getting in Car "<<carNum<<endl;
    }else{
      //if all passengers are in the car print message and tell driver
      cout<<"Visitor "<<num<<" is getting in Car "<<carNum<<endl;
      cout<<"All Visitors are in Car "<<carNum<<endl;
      readyToLeave[carNum]->Signal(carLock[carNum]);
    }
    
    //wait for driver to drive off
    cout<<"Visitor "<<num<<" is waiting for Car "<<carNum<<" to drive off"<<endl;
    waitExit[carNum]->Wait(carLock[carNum]);
    
    //release the lock
    carLock[carNum]->Release();
  }
  
}  

///////////////////////
//Ticket Taker       //
///////////////////////

void TicketTaker(){
  //get the lock
  while (true){
    lineLock->Acquire();
    
    //check the count to see if people are in line
    if (ticketLineCount > 0){
      //accept the ticket from the first person in line
      cout<<"Ticket accepted******************"<<endl;
      ticketLine->Signal(lineLock);
      //decrement the count of people in line
      ticketLineCount --;
    }else{
      //if no one is in line go to sleep
      cout<<"Ticket Taker is waiting for customers"<<endl;
      waitOnCustomers->Wait(lineLock);

    }
    
    //release the lock
    lineLock->Release();
  }
}

///////////////////////
//Valet              //
///////////////////////

//function for valet to park a car
void parkCar(int currentcar, int myNum){
  //get the lock
  parkingLock1->Acquire();

  //set the car you are working with
  currentcar = (int)carnumbersArrive->Remove();

  //Tell the driver they are there to help them
  cout<<"Valet "<<myNum<<" has approached Car "<<currentcar<<endl;
  readyToPark->Signal(parkingLock1);

  //decrement the number of cars in line to be parked
  inLine --;

  //release the lock
  parkingLock1->Release();

  //get the current car's lock
  carLock[currentcar]->Acquire();

  //wait for the keys from the driver
  cout<<"Valet "<<myNum<<" is waiting for Driver's Keys"<<endl;
  hasKeys[currentcar]->Wait(carLock[currentcar]);


  //message saying they recieved the keys
  cout<<"Valet "<<myNum<<" has received the keys"<<endl;

  //give the driver a parking token
  cout<<"Valet "<<myNum<<" hands over a parking token"<<endl;
  hasToken[currentcar]->Signal(carLock[currentcar]);

  //go and park the car
  cout<<"Valet "<<myNum<<" is parking the car"<<endl;

  //release the lock
  carLock[currentcar]->Release();


  //get a random number between 5 and 20
  int randomNum = rand()%21 + 5;
  
  //simulate time to get the car
  for(int i = randomNum; i>0; i--){
    currentThread->Yield();
  }

  //message saying car has finished being parked
  cout<<"Car "<<currentcar<<" has been parked"<<endl;

  //reset current car so it doesnt mess up other cars
  currentcar = -1;
}

void parkLimo(int currentcar, int myNum){
  //get the lock
  parkingLock1->Acquire();

  //set the car you are working with
  currentcar = (int)limoListToPark->Remove();

  //Tell the driver they are there to help them
  cout<<"Valet "<<myNum<<" has approached Limo "<<currentcar<<endl;
  limoReadyToPark->Signal(parkingLock1);

  //decrement the number of cars in line to be parked
  limoLine --;

  //release the lock
  parkingLock1->Release();

  //get the current car's lock
  limoLock[currentcar]->Acquire();

  //wait for the keys from the driver
  cout<<"Valet "<<myNum<<" is waiting for Limo Driver's Keys"<<endl;
  limoHasKeys[currentcar]->Wait(limoLock[currentcar]);

  //message saying they recieved the keys
  cout<<"Valet "<<myNum<<" has received the keys"<<endl;

  //give the driver a parking token
  cout<<"Valet "<<myNum<<" hands over a parking token"<<endl;
  limoHasToken[currentcar]->Signal(limoLock[currentcar]);

  //go and park the car
  cout<<"Valet "<<myNum<<" is parking the Limo"<<endl;

  //release the lock
  limoLock[currentcar]->Release();


  //get a random number between 5 and 20
  int randomNum = rand()%21 + 5;
  
  //simulate time to get the car
  for(int i = randomNum; i>0; i--){
    currentThread->Yield();
  }

  //message saying car has finished being parked
  cout<<"Limo "<<currentcar<<" has been parked"<<endl;

  //reset current car so it doesnt mess up other cars
  currentcar = -1;
}


//function for a valet to retrieve a car
void retrieveCar(int currentcar, int myNum){

  //get the lock
  parkingLock1->Acquire();

  //set the car the valet is working with
  currentcar = (int)carnumbersLeave->Remove();

  //decrement the driver waiting to leave coutnt
  driverWaiting --;

  //tells the driver they are there to help them
  cout<<"Valet "<<myNum<<" has approached Car "<<currentcar<<" and gets his Token"<<endl;
  leaving->Signal(parkingLock1);

  //release the lock
  parkingLock1->Release();

  //get the current car's lock
  carLock[currentcar]->Acquire();

  //wait for a parking token from the driver
  //cout<<"Valet "<<myNum<<" is waiting for a parking token"<<endl;
  //leaveToken[currentcar]->Wait(carLock[currentcar]); 

  //message saying they got the token
  //cout<<"Valet "<<myNum<<" has recieved a parking token"<<endl;
  
  //get the car from the parking lot
  cout<<"Valet "<<myNum<<"  is getting Car "<<currentcar<<endl;
  
  carLock[currentcar]->Release();
  //get a random number between 5 and 20
  int randomNum = rand()%21 + 5;
  
  //simulate time to get the car
  for(int i = randomNum; i>0; i--){
    currentThread->Yield();
  }

  carLock[currentcar]->Acquire();
  //tell the driver they have returned with the car
  cout<<"Valet "<<myNum<<" has returned with Car "<<currentcar<<endl;
  waitCarLeaving[currentcar]->Signal(carLock[currentcar]);

  //wait for a tip from the driver
  cout<<"Valet "<<myNum<<" is waiting for a tip"<<endl;
  Tip->Wait(carLock[currentcar]);

  //message that they recieved the tip
  cout<<"Valet "<<myNum<<" has recieved his tip"<<endl;

  //tell the driver that they can get in the car and leave
  cout<<"Car "<<currentcar<<" can get ready to leave"<<endl;
  canLeave[currentcar]->Signal(carLock[currentcar]);

  //release the lock
  carLock[currentcar]->Release();

  //reset current car so it doesnt mess up other cars
  currentcar = -1;

}


void retrieveLimo(int currentcar, int myNum){

  //get the lock
  parkingLock1->Acquire();

  //set the car the valet is working with
  currentcar = (int)limoListToLeave->Remove();

  //decrement the driver waiting to leave coutnt
  limoWaiting --;

  //tells the driver they are there to help them
  cout<<"Valet "<<myNum<<" has approached Limo "<<currentcar<<" and gets his toeken"<<endl;
  limoLeaving->Signal(parkingLock1);

  //release the lock
  parkingLock1->Release();

  //get the current car's lock
  limoLock[currentcar]->Acquire();

  //wait for a parking token from the driver
  //cout<<"Valet "<<myNum<<" is waiting for a parking token"<<endl;
  //limoLeaveToken[currentcar]->Wait(limoLock[currentcar]); 

  //message saying they got the token
  //cout<<"Valet "<<myNum<<" has recieved a parking token"<<endl;
  
  //get the car from the parking lot
  cout<<"Valet "<<myNum<<" is getting Limo "<<currentcar<<endl;

  limoLock[currentcar]->Release();
  //get a random number between 5 and 20
  int randomNum = rand()%21 + 5;
  
  //simulate time to get the car
  for(int i = randomNum; i>0; i--){
    currentThread->Yield();
  }

  limoLock[currentcar]->Acquire();

  //tell the driver they have returned with the car
  cout<<"Valet "<<myNum<<" has returned with Limo "<<currentcar<<endl;
  waitLimoLeaving[currentcar]->Signal(limoLock[currentcar]);

  //wait for a tip from the driver
  cout<<"Valet "<<myNum<<" is waiting for a tip"<<endl;
  //cout<<currentcar<<" limoLock: "<<limoLock[currentcar]<<endl;
  limoTip[currentcar]->Wait(limoLock[currentcar]);

  //message that they recieved the tip
  cout<<"Valet "<<myNum<<" has recieved his tip"<<endl;

  //tell the driver that they can get in the car and leave
  cout<<"Limo "<<currentcar<<" can get ready to leave"<<endl;
  limoCanLeave[currentcar]->Signal(limoLock[currentcar]);

  //release the lock
  limoLock[currentcar]->Release();

  //reset current car so it doesnt mess up other cars
  currentcar = -1;

}

bool correctTest = false;
int numInBack = 0;

void Valet(int valetNum){

  int currentcar = -1;
  int myNum = valetNum;
  
  while(true){
    //Order of priority: park limos, retrieve limos, retrieve cars, park cars
    if (limoLine>0){
      parkLimo(currentcar, myNum);
    }else if (limoWaiting != 0){
      retrieveLimo(currentcar, myNum);
    }else if(driverWaiting != 0){
      retrieveCar(currentcar, myNum);
    }else if (inLine != 0){
      parkCar(currentcar, myNum);
    } 
    
    //if another valet is already asleep get ready to go to back room
    if (onBench >= 1 && correctTest){
      breakLock->Acquire();
      //increment the on bench value
      onBench ++;
      //signal the manager that you need to go on break
      managerWaiting->Signal(breakLock);
      cout<<"Valet "<<myNum<<" is sleeping on the bench********"<<endl;
      //wait to be sent on break
      waitForBreak->Wait(breakLock);
      onBench --;
      numInBack ++;
      cout<<"Manager sends Valet "<<myNum<<" to the back room"<<endl;
      //go on break
      backRoom->Wait(breakLock);
      //sent back to work
      cout<<"Manager sends Valet "<<myNum<<" back to work"<<endl;
      numInBack --;
      breakLock->Release();
    }

    //update sum value
    sum = limoWaiting + limoLine + inLine + driverWaiting;
    
    parkingLock1->Acquire();
    //if there are no cars go to sleep
    if (inLine == 0 && driverWaiting == 0 && limoLine == 0 && limoWaiting == 0){
      onBench++;
      cout<<"Valet "<<myNum<<" is sleeping on the bench"<<endl;
      waitForCars->Wait(parkingLock1);
      onBench--;
    }
    
    
    parkingLock1->Release();

    /*
    //if there are 4 or more cars waiting ask for more help
    if (sum >= 4){
      breakLock->Acquire();
      //cout<<"***Asking Manager to send out another Valet***"<<endl;
      managerWaiting->Signal(breakLock);
      breakLock->Release();
    }
    */
  }
}

void sendOnBreak(){
  //signal the valet to go on break
  waitForBreak->Signal(breakLock);
  //      cout<<onBench<<endl;
      
  //decrement the count of valets on the bench
}

void goBackToWork(){
  //signal the valet to go back to work
  backRoom->Signal(breakLock);
}

void valetManager(){
  while (true){
    //get the lock
    breakLock->Acquire();
    //wait for a signal from the valets
    //managerWaiting->Wait(breakLock);
	
    //update the sum value to the newest amount
    sum = limoWaiting + limoLine + inLine + driverWaiting;

    if(onBench >= 1){
      //if more than one valet is on the bench send one on break
      sendOnBreak();
    }

    if (sum >= 4){
      //if (numInBack == 0)
	//cout<<"---------All Valets are working-------"<<endl;

      //if more than 4 cars are waiting to be handled send a valet back out
      goBackToWork();
    }
    //release the lock
    breakLock->Release();
  }
}

///////////////////////
//setup and run code //
///////////////////////

//global variables used to start each test
int numberOfCars;
int numberLimo;
int numTT;
int numValet;
int numVis;
bool manager = false;


void test1(){
  //initialize threads for the test
  Thread *driver;
  driver = new Thread("driver");

  passengers[0] = 2;

  Thread *valet;
  valet = new Thread("valet");

  Thread *tickettaker;
  tickettaker = new Thread("ticket taker");

  Thread** visitors;
  visitors = new Thread* [numVis];

  for (int i = 0; i <numVis; i ++){
    visitors[i] = new Thread("Visitor");
  }
  
  visInfo** data;
  data = new visInfo* [numVis];

  for (int i = 0; i <numVis; i ++){
    data[i] = new visInfo;
  }
  
  //fork the threads
  driver->Fork((VoidFunctionPtr)Driver,0);
  valet->Fork((VoidFunctionPtr)Valet,0);
  tickettaker->Fork((VoidFunctionPtr)TicketTaker,0);
  
  for (int i = 0; i <numVis; i ++){
    data[i]->name = "Visitor";
    data[i]->carNum = 0;
    data[i]->limoNum = -1;
    data[i]->limo = false;
    data[i]->visNum = i;
    visitors[i]->Fork((VoidFunctionPtr)Visitor,(int)data[i]);
  }

}
  
void test2(){
  Thread *driver;
  driver = new Thread("driver");

  Thread *valet0;
  valet0 = new Thread("valet");

  Thread *valet1;
  valet1 = new Thread("valet");

  Thread *limo0;
  limo0 = new Thread("limo");

  Thread *limo1;
  limo1 = new Thread("limo");

  Thread *limo2;
  limo2 = new Thread("limo");

  Thread *limo3;
  limo3 = new Thread("limo");

  Thread *limo4;
  limo4 = new Thread("limo");

  valet0->Fork((VoidFunctionPtr)Valet,0);
  valet1->Fork((VoidFunctionPtr)Valet,1);
  limo0->Fork((VoidFunctionPtr)limoDriver,0);
  limo1->Fork((VoidFunctionPtr)limoDriver,1);
  driver->Fork((VoidFunctionPtr)Driver,0);
  limo2->Fork((VoidFunctionPtr)limoDriver,2);
  limo3->Fork((VoidFunctionPtr)limoDriver,3);
  limo4->Fork((VoidFunctionPtr)limoDriver,4);
}

void test3(){
  Thread *driver0;
  driver0 = new Thread("driver");

  Thread *driver1;
  driver1 = new Thread("driver");

  Thread *driver2;
  driver2 = new Thread("driver");

  Thread *driver3;
  driver3 = new Thread("driver");

  Thread *driver4;
  driver4 = new Thread("driver");

  Thread *driver5;
  driver5 = new Thread("driver");

  Thread *driver6;
  driver6 = new Thread("driver");

  Thread *driver7;
  driver7 = new Thread("driver");

  Thread *driver8;
  driver8 = new Thread("driver");

  Thread *driver9;
  driver9 = new Thread("driver");

  Thread *valet0;
  valet0 = new Thread("valet");

  Thread *valet1;
  valet1 = new Thread("valet");

  Thread *valet2;
  valet2 = new Thread("valet");

  valet0->Fork((VoidFunctionPtr)Valet,0);
  valet1->Fork((VoidFunctionPtr)Valet,1);
  valet2->Fork((VoidFunctionPtr)Valet,2);
  driver0->Fork((VoidFunctionPtr)Driver,0);
  driver1->Fork((VoidFunctionPtr)Driver,1);
  driver2->Fork((VoidFunctionPtr)Driver,2);
  driver3->Fork((VoidFunctionPtr)Driver,3);
  driver4->Fork((VoidFunctionPtr)Driver,4);
  driver5->Fork((VoidFunctionPtr)Driver,5);
  driver6->Fork((VoidFunctionPtr)Driver,6);
  driver7->Fork((VoidFunctionPtr)Driver,7);
  driver8->Fork((VoidFunctionPtr)Driver,8);
  driver9->Fork((VoidFunctionPtr)Driver,9);

}
void test4(){
  Thread *valet0;
  valet0 = new Thread("valet");

  Thread *valet1;
  valet1 = new Thread("valet");

  Thread *valet2;
  valet2 = new Thread("valet");

  Thread *valet3;
  valet3 = new Thread("valet");

  Thread *valet4;
  valet4 = new Thread("valet");

  Thread *limo0;
  limo0 = new Thread("limo");

  Thread *limo1;
  limo1 = new Thread("limo");

  Thread *limo2;
  limo2 = new Thread("limo");

  Thread *limo3;
  limo3 = new Thread("limo");

  Thread *limo4;
  limo4 = new Thread("limo");

  Thread *limo5;
  limo5 = new Thread("limo");

  Thread *limo6;
  limo6 = new Thread("limo");

  Thread *limo7;
  limo7 = new Thread("limo");

  Thread *limo8;
  limo8 = new Thread("limo");

  Thread *limo9;
  limo9 = new Thread("limo");

  valet0->Fork((VoidFunctionPtr)Valet,0);
  valet1->Fork((VoidFunctionPtr)Valet,1);
  valet2->Fork((VoidFunctionPtr)Valet,2);
  valet3->Fork((VoidFunctionPtr)Valet,3);
  valet4->Fork((VoidFunctionPtr)Valet,4);
  limo0->Fork((VoidFunctionPtr)limoDriver,0);
  limo1->Fork((VoidFunctionPtr)limoDriver,1);
  limo2->Fork((VoidFunctionPtr)limoDriver,2);
  limo3->Fork((VoidFunctionPtr)limoDriver,3);
  limo4->Fork((VoidFunctionPtr)limoDriver,4);
  limo5->Fork((VoidFunctionPtr)limoDriver,5);
  limo6->Fork((VoidFunctionPtr)limoDriver,6);
  limo7->Fork((VoidFunctionPtr)limoDriver,7);
  limo8->Fork((VoidFunctionPtr)limoDriver,8);
  limo9->Fork((VoidFunctionPtr)limoDriver,9);
}

void test5(){
  Thread *driver0;
  driver0 = new Thread("driver");

  Thread *driver1;
  driver1 = new Thread("driver");

  Thread *driver2;
  driver2 = new Thread("driver");

  Thread *limo0;
  limo0 = new Thread("limo");

  Thread *limo1;
  limo1 = new Thread("limo");

  driver0->Fork((VoidFunctionPtr)Driver,0);
  driver1->Fork((VoidFunctionPtr)Driver,1);
  driver2->Fork((VoidFunctionPtr)Driver,2);
  limo0->Fork((VoidFunctionPtr)limoDriver,0);
  limo1->Fork((VoidFunctionPtr)limoDriver,1);

}

void test6(){
  correctTest = true;

  Thread *valet0;
  valet0 = new Thread("valet");

  Thread *valet1;
  valet1 = new Thread("valet");

  Thread *valet2;
  valet2 = new Thread("valet");

  Thread *driver0;
  driver0 = new Thread("driver");

  Thread *limo0;
  limo0 = new Thread("limo");

  Thread *limo1;
  limo1 = new Thread("limo");

  Thread *limo2;
  limo2 = new Thread("limo");

  Thread *limo3;
  limo3 = new Thread("limo");

  Thread *limo4;
  limo4 = new Thread("limo");

  Thread *vmanager;
  vmanager = new Thread("valet manager");

  valet0->Fork((VoidFunctionPtr)Valet,0);
  valet1->Fork((VoidFunctionPtr)Valet,1);
  valet2->Fork((VoidFunctionPtr)Valet,2);
  driver0->Fork((VoidFunctionPtr)Driver,0);
  limo0->Fork((VoidFunctionPtr)limoDriver,0);
  limo1->Fork((VoidFunctionPtr)limoDriver,1);
  limo2->Fork((VoidFunctionPtr)limoDriver,2);
  limo3->Fork((VoidFunctionPtr)limoDriver,3);
  limo4->Fork((VoidFunctionPtr)limoDriver,4);
  vmanager->Fork((VoidFunctionPtr)valetManager,0);

}

void test7(){
  Thread *driver0;
  driver0 = new Thread("driver");

  Thread *limo0;
  limo0 = new Thread("limo");

  Thread *limo1;
  limo1 = new Thread("limo");

  Thread *valet0;
  valet0 = new Thread("valet");

  Thread *valet1;
  valet1 = new Thread("valet");

  Thread** visitors;
  visitors = new Thread* [numVis];

  for (int i = 0; i <numVis; i ++){
    visitors[i] = new Thread("Visitor");
  }
  
  visInfo** data;
  data = new visInfo* [numVis];

  for (int i = 0; i <numVis; i ++){
    data[i] = new visInfo;
  }

  passengers[0] = 4;
  limoPassengers[0] = 2;
  limoPassengers[1] = 2;

  valet0->Fork((VoidFunctionPtr)Valet,0);
  valet1->Fork((VoidFunctionPtr)Valet,1);
  driver0->Fork((VoidFunctionPtr)Driver,0);
  limo0->Fork((VoidFunctionPtr)limoDriver,0);
  limo1->Fork((VoidFunctionPtr)limoDriver,1);

  for (int i = 0; i <4; i ++){
    data[i]->name = "Visitor";
    data[i]->carNum = 0;
    data[i]->limoNum = -1;
    data[i]->limo = false;
    data[i]->visNum = i;
    visitors[i]->Fork((VoidFunctionPtr)Visitor,(int)data[i]);
  }
  for (int i = 4; i <6; i ++){
    data[i]->name = "Visitor";
    data[i]->carNum = -1;
    data[i]->limoNum = 0;
    data[i]->limo = true;
    data[i]->visNum = i;
    visitors[i]->Fork((VoidFunctionPtr)Visitor,(int)data[i]);
  }
  for (int i = 6; i <8; i ++){
    data[i]->name = "Visitor";
    data[i]->carNum = -1;
    data[i]->limoNum = 1;
    data[i]->limo = true;
    data[i]->visNum = i;
    visitors[i]->Fork((VoidFunctionPtr)Visitor,(int)data[i]);
  }

}
void test8(){
  Thread *driver0;
  driver0 = new Thread("driver");

  Thread *limo0;
  limo0 = new Thread("limo");

  Thread *limo1;
  limo1 = new Thread("limo");

  Thread *valet0;
  valet0 = new Thread("valet");

  Thread *valet1;
  valet1 = new Thread("valet");

  Thread *tickettaker;
  tickettaker = new Thread("ticket taker");

  Thread** visitors;
  visitors = new Thread* [numVis];

  for (int i = 0; i <numVis; i ++){
    visitors[i] = new Thread("Visitor");
  }
  
  visInfo** data;
  data = new visInfo* [numVis];

  for (int i = 0; i <numVis; i ++){
    data[i] = new visInfo;
  }

  passengers[0] = 4;
  limoPassengers[0] = 2;
  limoPassengers[1] = 2;

  valet0->Fork((VoidFunctionPtr)Valet,0);
  valet1->Fork((VoidFunctionPtr)Valet,1);
  tickettaker->Fork((VoidFunctionPtr)TicketTaker,0);
  driver0->Fork((VoidFunctionPtr)Driver,0);
  limo0->Fork((VoidFunctionPtr)limoDriver,0);
  limo1->Fork((VoidFunctionPtr)limoDriver,1);

  for (int i = 0; i <4; i ++){
    data[i]->name = "Visitor";
    data[i]->carNum = 0;
    data[i]->limoNum = -1;
    data[i]->limo = false;
    data[i]->visNum = i;
    visitors[i]->Fork((VoidFunctionPtr)Visitor,(int)data[i]);
  }
  for (int i = 4; i <6; i ++){
    data[i]->name = "Visitor";
    data[i]->carNum = -1;
    data[i]->limoNum = 0;
    data[i]->limo = true;
    data[i]->visNum = i;
    visitors[i]->Fork((VoidFunctionPtr)Visitor,(int)data[i]);
  }
  for (int i = 6; i <8; i ++){
    data[i]->name = "Visitor";
    data[i]->carNum = -1;
    data[i]->limoNum = 1;
    data[i]->limo = true;
    data[i]->visNum = i;
    visitors[i]->Fork((VoidFunctionPtr)Visitor,(int)data[i]);
  }


}
void test9(){
  Thread *driver0;
  driver0 = new Thread("driver");

  Thread *limo0;
  limo0 = new Thread("limo");

  Thread *valet0;
  valet0 = new Thread("valet");

  Thread *valet1;
  valet1 = new Thread("valet");

  Thread *tickettaker;
  tickettaker = new Thread("ticket taker");

  Thread *visitor0;
  visitor0 = new Thread("vis0");

  limoPassengers[0] = 1;

  visInfo *data0 = new visInfo();

  valet0->Fork((VoidFunctionPtr)Valet,0);
  valet1->Fork((VoidFunctionPtr)Valet,1);
  tickettaker->Fork((VoidFunctionPtr)TicketTaker,0);
  driver0->Fork((VoidFunctionPtr)Driver,0);
  limo0->Fork((VoidFunctionPtr)limoDriver,0);

  data0->name = "Visitor";
  data0->carNum = -1;
  data0->limoNum = 0;
  data0->limo = true;
  data0->visNum = 0;
  visitor0->Fork((VoidFunctionPtr)Visitor,(int)data0);


}

void test10(){
  Thread *driver0;
  driver0 = new Thread("driver");

  Thread *limo0;
  limo0 = new Thread("limo");

  Thread *valet0;
  valet0 = new Thread("valet");

  Thread *valet1;
  valet1 = new Thread("valet");

  Thread *tickettaker;
  tickettaker = new Thread("ticket taker");

  Thread** visitors;
  visitors = new Thread* [numVis];

  for (int i = 0; i <numVis; i ++){
    visitors[i] = new Thread("Visitor");
  }
  
  visInfo** data;
  data = new visInfo* [numVis];

  for (int i = 0; i <numVis; i ++){
    data[i] = new visInfo;
  }

  passengers[0] = 2;
  limoPassengers[0] = 2;

  valet0->Fork((VoidFunctionPtr)Valet,0);
  valet1->Fork((VoidFunctionPtr)Valet,1);
  tickettaker->Fork((VoidFunctionPtr)TicketTaker,0);
  driver0->Fork((VoidFunctionPtr)Driver,0);
  limo0->Fork((VoidFunctionPtr)limoDriver,0);

  for (int i = 0; i <2; i ++){
    data[i]->name = "Visitor";
    data[i]->carNum = 0;
    data[i]->limoNum = -1;
    data[i]->limo = false;
    data[i]->visNum = i;
    visitors[i]->Fork((VoidFunctionPtr)Visitor,(int)data[i]);
  }

  for (int i = 2; i <4; i ++){
    data[i]->name = "Visitor";
    data[i]->carNum = -1;
    data[i]->limoNum = 0;
    data[i]->limo = true;
    data[i]->visNum = i;
    visitors[i]->Fork((VoidFunctionPtr)Visitor,(int)data[i]);
  }

}
bool yesCars = true;
bool yesLimo = true;
int visPerVehicle = 0;

void testEverything(){
  correctTest = true;

  Thread *driver0;
  driver0 = new Thread("driver");

  Thread *driver1;
  driver1 = new Thread("driver");

  Thread *driver2;
  driver2 = new Thread("driver");

  Thread *driver3;
  driver3 = new Thread("driver");

  Thread *driver4;
  driver4 = new Thread("driver");

  Thread *driver5;
  driver5 = new Thread("driver");

  Thread *limo0;
  limo0 = new Thread("limo");

  Thread *limo1;
  limo1 = new Thread("limo");

  Thread *limo2;
  limo2 = new Thread("limo");

  Thread *valet0;
  valet0 = new Thread("valet");

  Thread *valet1;
  valet1 = new Thread("valet");

  Thread *valet2;
  valet2 = new Thread("valet");

  Thread *tickettaker;
  tickettaker = new Thread("ticket taker");

  Thread** visitors;
  visitors = new Thread* [numVis];

  Thread *vmanager;
  vmanager = new Thread("valet manager");
  

  for (int i = 0; i <numVis; i ++){
    visitors[i] = new Thread("Visitor");
  }
  
  visInfo** data;
  data = new visInfo* [numVis];

  for (int i = 0; i <numVis; i ++){
    data[i] = new visInfo;
  }

  passengers[0] = 2;
  passengers[1] = 2;
  passengers[2] = 2;
  passengers[3] = 2;
  passengers[4] = 2;
  passengers[5] = 2;

  limoPassengers[0] = 3;
  limoPassengers[1] = 3;
  limoPassengers[2] = 3;

  vmanager->Fork((VoidFunctionPtr)valetManager,0);
  valet0->Fork((VoidFunctionPtr)Valet,0);
  valet1->Fork((VoidFunctionPtr)Valet,1);
  valet2->Fork((VoidFunctionPtr)Valet,2);
  tickettaker->Fork((VoidFunctionPtr)TicketTaker,0);
  driver0->Fork((VoidFunctionPtr)Driver,0);
  driver1->Fork((VoidFunctionPtr)Driver,1);
  driver2->Fork((VoidFunctionPtr)Driver,2);
  driver3->Fork((VoidFunctionPtr)Driver,3);
  driver4->Fork((VoidFunctionPtr)Driver,4);
  driver5->Fork((VoidFunctionPtr)Driver,5);
  limo0->Fork((VoidFunctionPtr)limoDriver,0);
  limo1->Fork((VoidFunctionPtr)limoDriver,1);
  limo2->Fork((VoidFunctionPtr)limoDriver,2);

  for (int i = 0; i <2; i ++){
    data[i]->name = "Visitor";
    data[i]->carNum = 0;
    data[i]->limoNum = -1;
    data[i]->limo = false;
    data[i]->visNum = i;
    visitors[i]->Fork((VoidFunctionPtr)Visitor,(int)data[i]);
  }
  for (int i = 2; i <4; i ++){
    data[i]->name = "Visitor";
    data[i]->carNum = 1;
    data[i]->limoNum = -1;
    data[i]->limo = false;
    data[i]->visNum = i;
    visitors[i]->Fork((VoidFunctionPtr)Visitor,(int)data[i]);
  }
  for (int i = 4; i <6; i ++){
    data[i]->name = "Visitor";
    data[i]->carNum = 2;
    data[i]->limoNum = -1;
    data[i]->limo = false;
    data[i]->visNum = i;
    visitors[i]->Fork((VoidFunctionPtr)Visitor,(int)data[i]);
  }
  for (int i = 6; i <8; i ++){
    data[i]->name = "Visitor";
    data[i]->carNum = 3;
    data[i]->limoNum = -1;
    data[i]->limo = false;
    data[i]->visNum = i;
    visitors[i]->Fork((VoidFunctionPtr)Visitor,(int)data[i]);
  }
  for (int i = 8; i <10; i ++){
    data[i]->name = "Visitor";
    data[i]->carNum = 4;
    data[i]->limoNum = -1;
    data[i]->limo = false;
    data[i]->visNum = i;
    visitors[i]->Fork((VoidFunctionPtr)Visitor,(int)data[i]);
  }
  for (int i = 10; i <12; i ++){
    data[i]->name = "Visitor";
    data[i]->carNum = 5;
    data[i]->limoNum = -1;
    data[i]->limo = false;
    data[i]->visNum = i;
    visitors[i]->Fork((VoidFunctionPtr)Visitor,(int)data[i]);
  }
   
  for (int i = 12; i <15; i ++){
    data[i]->name = "Visitor";
    data[i]->carNum = -1;
    data[i]->limoNum = 0;
    data[i]->limo = true;
    data[i]->visNum = i;
    visitors[i]->Fork((VoidFunctionPtr)Visitor,(int)data[i]);
  }
  for (int i = 15; i <18; i ++){
    data[i]->name = "Visitor";
    data[i]->carNum = -1;
    data[i]->limoNum = 1;
    data[i]->limo = true;
    data[i]->visNum = i;
    visitors[i]->Fork((VoidFunctionPtr)Visitor,(int)data[i]);
  }
  for (int i = 18; i <21; i ++){
    data[i]->name = "Visitor";
    data[i]->carNum = -1;
    data[i]->limoNum = 2;
    data[i]->limo = true;
    data[i]->visNum = i;
    visitors[i]->Fork((VoidFunctionPtr)Visitor,(int)data[i]);
  }
}
  /*
  //correctTest = true;
  int count = 0;

  Thread** drivers;
  drivers = new Thread* [numberOfCars];

  for (int i = 0; i <numberOfCars;i++)
    drivers[i] = new Thread("driver");

  Thread** limoDrivers;
  limoDrivers = new Thread* [numberLimo];
  
  for (int i = 0; i <numberLimo;i++)
    limoDrivers[i] = new Thread("Limo Drivers");

  Thread** valets;
  valets = new Thread* [numValet];

  for (int i = 0; i<numValet; i++)
    valets[i] = new Thread ("Valet");

  Thread** visitors;
  visitors = new Thread* [numVis];

  for (int i = 0; i<numVis; i++)
    visitors[i] = new Thread ("Visitor");

  visInfo** data;
  data = new visInfo* [numVis];

  for (int i = 0; i <numVis; i ++)
    data[i] = new visInfo;

  for (int i = 0; i < numberOfCars; i++)
    passengers[i] = visPerVehicle;

  for (int i = 0; i < numberLimo; i++)
    limoPassengers[i] = visPerVehicle;

  
  Thread* ticketTaker;
  ticketTaker = new Thread ("Ticket Taker");

  Thread* valetManager;
  valetManager = new Thread ("Valet Manager");

  for (int i = 0; i <numValet;i++)
    valets[i]->Fork((VoidFunctionPtr)Valet,i);
  
  for (int i = 0; i <numberOfCars;i++)
    drivers[i]->Fork((VoidFunctionPtr)Driver,i);
  
  for (int i = 0; i <numberLimo;i++)
   limoDrivers[i]->Fork((VoidFunctionPtr)limoDriver,i);
  
  ticketTaker->Fork((VoidFunctionPtr)TicketTaker,0);
  //valetManager->Fork((VoidFunctionPtr)valetManager,0);
  
  for (int j = 0; j <numberOfCars; j++){
    for (int i = 0; i <visPerVehicle; i ++){
      data[i]->name = "Visitor";
      data[i]->carNum = j;
      data[i]->limoNum = -1;
      data[i]->limo = false;
      data[i]->visNum = count;
      count++;
      visitors[i]->Fork((VoidFunctionPtr)Visitor,(int)data[i]);
    }
  }
  
  for (int j = 0; j <numberLimo; j++){
    for (int i = 0; i <visPerVehicle; i ++){
      data[count]->name = "Visitor";
      data[count]->carNum = -1;
      data[count]->limoNum = j;
      data[count]->limo = true;
      data[count]->visNum = count;
      visitors[count]->Fork((VoidFunctionPtr)Visitor,(int)data[count]);
      count++;
    }
  }
  */


void Problem2(){

  int input = -1;
  /*
  cout<<"1. 1 Car with visitors and 1 Valet and a Ticket Taker"<<endl;
  cout<<"2. 1 Car 5 Limos and 2 valets with no visitors"<<endl;
  cout<<"3. 10 Cars and 3 valets with no visitors"<<endl;
  cout<<"4. 10 Limos and 5 valets and a valet manager"<<endl;
  cout<<"5. 3 Cars 3 Limos 2 visitors in car 0 and 2 visitors in Limo 0"<<endl;
  cout<<"6. 1 car 5 Limos 3 Valets and a Valet manager, no Visitors"<<endl;
  cout<<"7. 1 Car 2 limos and 2 valets, 4 visitors in the car and 2 in each limo"<<endl;
  cout<<"8. 1 Car 2 limos and 2 valets, 4 visitors in the car and 2 in each limo and also a ticket taker"<<endl;
  cout<<"9. 1 Car 1 limo 2 valet 1 visitor in the car and a ticket taker"<<endl;
  cout<<"10. 1 car 1 limo 2 valets 2 visitors in the car and 2 in the limo and a ticket taker"<<endl;
  */
  cout<<"Please see WRITEUP.txt for test details"<<endl;
  cout<<"Please enter a test number 1 - 11: ";
  cin>>input;

  if (input == 1){
    numberOfCars = 1;
    numberLimo = 1; //cannot be zero but no limos will be started
    numTT = 1;
    numValet = 2;
    numVis = 2;
  }else if (input == 2){
    numberOfCars = 1;
    numberLimo = 5;
    numTT = 0;
    numValet = 2;
    numVis = 0;
  }else if (input == 3){
    numberOfCars = 10;
    numberLimo = 1; //cannot be zero but no limos will be started
    numTT = 1;
    numValet = 3;
    numVis = 0;
  }else if (input == 4){
    numberOfCars = 1;//cannot be zero but no cars will be started
    numberLimo = 10;
    numTT = 0;
    numValet = 5;
    numVis = 0;
    manager = true;
  }else if (input == 5){
    numberOfCars = 3;
    numberLimo = 2;
    numTT = 0;
    numValet = 0;
    numVis = 4;
  }else if (input == 6){
    numberOfCars = 1;
    numberLimo = 5;
    numTT = 0;
    numValet = 3;
    numVis = 0;
    manager = true;
  }else if (input == 7){
    numberOfCars = 1;
    numberLimo = 2;
    numTT = 0;
    numValet = 2;
    numVis = 8;
  }else if (input == 8){
    numberOfCars = 1;
    numberLimo = 2;
    numTT = 1;
    numValet = 2;
    numVis = 8;
  }else if (input == 9){
    numberOfCars = 1;
    numberLimo = 1;
    numTT = 1;
    numValet = 2;
    numVis = 1;
  }else if (input == 10){
    numberOfCars = 1;
    numberLimo = 1;
    numTT = 1;
    numValet = 2;
    numVis = 4;
  }else if (input == 11){
    cout<<"This test will run with the following data:"<<endl;
    cout<<"6 Cars with 2 Visitors each"<<endl;
    cout<<"2 Limos with 3 Visitors each"<<endl;
    cout<<"3 Valets"<<endl;
    cout<<"1 Ticket Taker"<<endl;
    cout<<"1 Valet Manager"<<endl;

    numberOfCars = 6;
    numberLimo = 3;
    numValet = 3;
    numTT = 1;
    manager = true;
    numVis = 21;
    /*
    string  query;
    numberOfCars = 1;
    numberLimo = 1;
    cout<<"Do you want Cars y or n: ";
    cin>>query;
    
    if (query == "y" || query == "yes"){
      cout<<"Entering 0 will be translated to a 1"<<endl;
      cout<<"How many Cars do you want: ";
      cin>>numberOfCars;
    }
    
    cout<<"Do you want Limos y or n: ";
    cin>>query;

    if (query == "y" || query == "yes"){
      cout<<"Entering 0 will be translated to a 1"<<endl;
      cout<<"How many Limos do you want: ";
      cin>>numberLimo;
    }
    
    cout<<"How many Valets do you want: ";
    cin>>numValet;

    cout<<"How many Visitors per car do you want *Each car or limo will have the same number of Visitors*: ";
    cin>>visPerVehicle;

    if (numberOfCars == 0){
      numberOfCars = 1;
    }
    
    if (numberLimo == 0){
      numberLimo = 1;
    }
    numVis = visPerVehicle * (numberOfCars + numberLimo);
    */
  }

  //allocation of memory based on test number defined above
  passengers = new int[numberOfCars];
  limoPassengers = new int[numberLimo];

  outOfCar = new int[numberOfCars];
  limoOutOfCar = new int[numberLimo];
  
  for (int i = 0; i<numberOfCars; i++)
    passengers[0] = 0;
  
  for (int i = 0; i<numberLimo +1; i++)
    limoPassengers[0] = 0;

  for (int i = 0; i<numberOfCars; i++)
    outOfCar[0] = 0;

  for (int i = 0; i<numberLimo+1; i++)
    limoOutOfCar[0] = 0;

  //allocating memory for car locks
  carLock = new Lock* [numberOfCars];
  for(int i = 0; i<numberOfCars; i++)
    carLock[i] = new Lock("test");

  //allocating memory for limo locks
  limoLock = new Lock* [numberLimo];
  for(int i = 0; i<(numberLimo); i++){
    limoLock[i] = new Lock ("limo Lock");
  }
  
  parkingLock1 = new Lock("parking Lock");

  lineLock = new Lock("line lock");

  breakLock = new Lock("break lock");

  driverWaitingCV = new Condition* [numberOfCars];
  for(int i = 0; i<numberOfCars; i++) 
    driverWaitingCV[i] = new Condition("driver waiting");

  visitorExit = new Condition* [numberOfCars];
  for(int i = 0; i<numberOfCars; i++) 
    visitorExit[i] = new Condition("Visitor can exit");

  visitorLimoExit = new Condition* [numberLimo];
  for(int i = 0; i<numberLimo; i++) 
    visitorLimoExit[i] = new Condition("Visitor can exit");

  readyToLeave = new Condition* [numberOfCars];
  for(int i = 0; i<numberOfCars; i++) 
    readyToLeave[i] = new Condition("ready to leave");

  limoReadyToLeave = new Condition* [numberLimo];
  for(int i = 0; i<numberLimo; i++) 
    limoReadyToLeave[i] = new Condition("ready to leave");


  waitToLeave = new Condition* [numberLimo];
  for(int i = 0; i<numberOfCars; i++) 
    waitToLeave[i] = new Condition("waiting to leave");

  limoWaitToLeave = new Condition* [numberLimo];
  for(int i = 0; i<numberLimo; i++) 
    limoWaitToLeave[i] = new Condition("waiting to leave");

  waitExit = new Condition* [numberOfCars];
  for(int i = 0; i<numberOfCars; i++) 
    waitExit[i] = new Condition("waiting to drive off");

  limoWaitExit = new Condition* [numberLimo];
  for(int i = 0; i<numberLimo; i++) 
    limoWaitExit[i] = new Condition("waiting to drive off");

  canLeave = new Condition* [numberOfCars];
  for(int i = 0; i<numberOfCars; i++) 
    canLeave[i] = new Condition("can leave the museum");

  limoCanLeave = new Condition* [numberLimo];
  for(int i = 0; i<numberLimo; i++) 
    limoCanLeave[i] = new Condition("can leave the museum");

  leaving = new Condition ("leaving");
  limoLeaving = new Condition ("leaving");

  readyToPark = new Condition ("ready to park");
  limoReadyToPark = new Condition("limo ready to park");

  limoWaitingCV = new Condition* [numberLimo];
  for(int i = 0; i<numberLimo; i++) 
    limoWaitingCV[i] = new Condition("driver waiting");
  
  hasKeys = new Condition* [numberOfCars];
  for(int i = 0; i<numberOfCars; i++) 
    hasKeys[i] = new Condition ("waiting for keys");

  limoHasKeys = new Condition* [numberLimo];
  for(int i = 0; i<numberLimo; i++) 
    limoHasKeys[i] = new Condition ("waiting for Limo keys");

  hasToken = new Condition* [numberOfCars];
  for(int i = 0; i<numberOfCars; i++) 
    hasToken[i] = new Condition("waiting for parking token");

  limoHasToken = new Condition* [numberLimo];
  for(int i = 0; i<numberLimo; i++) 
    limoHasToken[i] = new Condition("waiting for Limo parking token");

  leaveToken = new Condition* [numberOfCars];
  for(int i = 0; i<numberOfCars; i++) 
    leaveToken[i] = new Condition("waiting for token so car can leave");

  limoLeaveToken = new Condition* [numberLimo];
  for(int i = 0; i<(numberLimo); i++) 
    limoLeaveToken[i] = new Condition("waiting for token so car can leave");

  Tip = new Condition ("Waiting for a tip");

  limoTip = new Condition* [numberLimo];
  for(int i = 0; i<(numberLimo ); i++) 
    limoTip[i] = new Condition ("Waiting for a tip");
  
  ticketLine = new Condition("wait for ticket accpetance");

  waitOnCustomers = new Condition("wait for customers");

  waitForCars = new Condition("wait for cars");

  waitForBreak = new Condition("wait for Break");

  waitCarLeaving = new Condition* [numberOfCars];
  for(int i = 0; i<numberOfCars; i++) 
    waitCarLeaving[i] = new Condition("wait to leave");

  waitLimoLeaving = new Condition* [numberLimo];
  for(int i = 0; i<(numberLimo ); i++) 
    waitLimoLeaving[i] = new Condition("wait to leave");

  managerWaiting = new Condition("go on break");
  backRoom = new Condition("In the back");

  carnumbersArrive = new List;
  carnumbersLeave = new List;
  limoListToPark = new List;
  limoListToLeave = new List;

  switch (input){
  case (1): test1();
    break;
  case (2): test2();
    break;
  case (3): test3();
    break;
  case (4): test4();
    break;
  case (5): test5();
    break;
  case (6): test6();
    break;
  case (7): test7();
    break;
  case (8): test8();
    break;
  case (9): test9();
    break;
  case (10): test10();
    break;
  case (11): testEverything();
    break;
  default: cout<<"No corresponding test to that number!!!!!!!"<<endl;
  }

}
